package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.RedisConstants;
import com.ruoyi.common.service.RedisService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.req.DataTableReq;
import com.ruoyi.system.domain.req.FieldRule;
import com.ruoyi.system.domain.req.ProcessData;
import com.ruoyi.system.domain.vo.DataTableVo;
import com.ruoyi.system.domain.vo.TemplateTableRelVo;
import com.ruoyi.system.mapper.DynamicMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.utils.FileDataUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;

@Slf4j
@Service
public class DatabaleServiceImpl implements IDatabaleService {
    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static String YYYY_MM_DD = "yyyy-MM-dd";
    @Resource
    private IFieldDataService fieldDataService;

    @Resource
    private ITableDataService tableDataService;

    @Resource
    private ITemplateTableRelService templateTableRelService;

    @Resource
    private DynamicMapper dynamicMapper;

    @Resource
    private RedisService redisService;

    @Resource
    private IGenerateRuleService generateRuleService;

    @Resource
    private ICollectRuleService collectRuleService;

    @Override
    public DataTableVo selectDataTableList(DataTableReq dataTableReq) {
        // 获取模板信息
        // 字段中文名称
        List<String> columnCnName = new ArrayList<>();
        // 字段英文名称
        List<String> columnEnName = new ArrayList<>();
        // 字段结果集
        List<Map<String, Object>> mapList = new ArrayList<>();
        TemplateTableRel templateTableRel = new TemplateTableRel();
        templateTableRel.setTemplateId(dataTableReq.getTemplateId());
        List<TemplateTableRelVo> templateList = templateTableRelService.selectTemplateTableRelList(templateTableRel);
        DataTableVo dataTableVo = new DataTableVo();
        dataTableVo.setTableCnName(templateList.get(0).getTableCnName());
        dataTableVo.setTableEnName(templateList.get(0).getTableEnName());
        templateList.forEach(templateTableRelVo -> {
            columnCnName.add(templateTableRelVo.getFieldName());
            columnEnName.add(templateTableRelVo.getFieldEnName());
        });

        dataTableVo.setColumnCnName(columnCnName);
        dataTableVo.setColumnEnName(columnEnName);
        Long count = dynamicMapper.selectCountDynamic(dataTableVo.getTableEnName());
        dataTableVo.setTotal(count);
        if (count > 0) {
            mapList = dynamicMapper.selectDynamic(dataTableVo.getTableEnName(), StringUtils.join(columnEnName, ","), dataTableReq.getPageSize() * (dataTableReq.getPageNum() - 1), dataTableReq.getPageSize());
        }
        dataTableVo.setMapList(mapList);
        return dataTableVo;
    }

    @Override
    public DataTableVo generateData(DataTableReq dataTableReq) throws InterruptedException {
        DataTableVo dataTableVo = new DataTableVo();
        List<ProcessData> processList = new ArrayList<>();
        String redisId = RedisConstants.PROGRESS_ + dataTableReq.getTemplateId() + "_" + dataTableReq.getUuid();

        // 数据生成进度
        updateMsgByprocess(processList, "开始模拟生成数据", redisId, Constants.FLAG_1);

        // 建立连接
        Random random = new Random();
        updateMsgByprocess(processList, "读取数据配置", redisId, Constants.FLAG_2);
        Thread.sleep(random.nextInt(1001) + 1000);
        updateMsgByprocess(processList, "数据配置读取完成", redisId, Constants.FLAG_2);

        // 开始生成数据
        Map<String, Object> params = new HashMap<>();
        TableData tableData = tableDataService.selectTableDataByTableId(dataTableReq.getTableId());
        params.put("tableName", tableData.getTableEnName());

        updateMsgByprocess(processList, "开始读取python脚本配置", redisId, Constants.FLAG_3);
        // 模拟数据
        List<FieldRule> ruleList = dataTableReq.getRuleList();

        Map<String, List<String>> listMap = new HashMap<>();
        Thread.sleep(random.nextInt(1001) + 1000);
        updateMsgByprocess(processList, "读取python脚本配置完成", redisId, Constants.FLAG_3);

        updateMsgByprocess(processList, "模拟生成数据" + dataTableReq.getDataSize() + "个样本数据", redisId, Constants.FLAG_4);
        Map<String,List<String>> collectRowList = new HashMap<>();
        if(dataTableReq.getDataType() == 1){
            // 模拟数据
            for (FieldRule fieldRule : ruleList) {
                // 获取模板数据
                GenerateRule generateRule = generateRuleService.selectGenerateRuleByRuleId(fieldRule.getRuleId());
                File file = FileDataUtils.createFile(generateRule.getRuleName() + ".py", generateRule.getRuleCmd()); // 获取临时文件
                JSONObject jsonParam = JSONObject.parse(generateRule.getRuleText());

                // 获取字段
                FieldData fieldData = fieldDataService.selectFieldDataByFieldId(fieldRule.getTableFieldId());
                String fileName = fieldData.getFieldEnName();

                // python执行脚本并生成数据
                List<String> dataList = FileDataUtils.generateData(file.getPath(), jsonParam.get("arg1").toString(), jsonParam.get("arg2").toString(), dataTableReq.getDataSize().toString());
                listMap.put(fileName, dataList);
                updateMsgByprocess(processList, fieldData.getFieldCnName() + "正在生成中,生成" + dataTableReq.getDataSize() + "条数据", redisId, Constants.FLAG_4);
            }
        }else{
            // 获取模板数据
            CollectRule collectRule = collectRuleService.selectCollectRuleByCollectId(dataTableReq.getCollectId());
            File file = FileDataUtils.createFile(collectRule.getCollectName() + ".py", collectRule.getCollectCmd()); // 获取临时文件

            // python执行脚本并生成数据
            collectRowList = FileDataUtils.generateCollectData(file.getPath());
            updateMsgByprocess(processList, "模拟数据正在生成中,生成" + dataTableReq.getDataSize() + "条数据", redisId, Constants.FLAG_4);
            //            List<Integer> dataList = FileDataUtils.generateData(file.getPath(), jsonParam.get("arg1").toString(), jsonParam.get("arg2").toString(), dataTableReq.getDataSize().toString());
//            listMap.put(fileName, dataList);
        }

        Thread.sleep(random.nextInt(1001) + 1000);
        updateMsgByprocess(processList, "脚本生成模拟数据完成", redisId, Constants.FLAG_4);

        List<String> columnList = new ArrayList<>();
        List<List<String>> rowList = new ArrayList<>();
        //列数据
        if(dataTableReq.getDataType() == 1){
            columnList = new ArrayList<>(listMap.keySet());
            params.put("columns", columnList); // 设置字段列表
        }else{
//            Set<String> columnTempList =  collectRowList.keySet();
            // 翻译数据 --- 中文翻译成英文
//            for (int i = 0; i < columnTempList.size() ; i++) {
//                FieldData fieldData = fieldDataService.getOne(new LambdaQueryWrapper<FieldData>().eq(FieldData::getFieldCnName, columnTempList[i]).eq(FieldData::getTableId, dataTableReq.getTableId()));
//                if(null != fieldData){
//                    columnList.add(fieldData.getFieldEnName());
//                }
//            }

            int size = 0;
            List<String> cnList = new ArrayList<>(); // 存放中文名称
            for (Map.Entry<String, List<String>> entry : collectRowList.entrySet()) {
                String k = entry.getKey();
                List<String> v = entry.getValue();
                FieldData fieldData = fieldDataService.getOne(new LambdaQueryWrapper<FieldData>().eq(FieldData::getFieldCnName, k).eq(FieldData::getTableId, dataTableReq.getTableId()));
                if(null != fieldData){
                    columnList.add(fieldData.getFieldEnName());
                    cnList.add(fieldData.getFieldCnName());
                }
                size = v.size();
            }


            for (int i = 0; i < size; i++) {
                List<String> row = new ArrayList<>();  // 行数据
                for (String fieldName : cnList) {
                    List<String> lieList = collectRowList.get(fieldName); // 列数据
                    row.add(lieList.get(i));
                }
                rowList.add(row); // 所有的列数据
            }

            params.put("columns", columnList); // 设置字段列表
        }

        //行数据
        if(dataTableReq.getDataType() == 1 ){
            for (int i = 0; i < dataTableReq.getDataSize(); i++) {
                List<String> list = new ArrayList<>();
                for (String fieldName : columnList) {
                    String value = listMap.get(fieldName).get(i);

                    // 气候处理
                    if(fieldName.equals("climate")){
                        int climate =  Math.abs(Integer.parseInt(listMap.get("climate").get(i)));
                        if(climate%5 == 0){
                            value = "晴天";
                        }
                        if(climate%5 == 1){
                            value = "阴天";
                        }
                        if(climate%5 == 2){
                            value = "雨天";
                        }
                        if(climate%5 == 3){
                            value = "雷雨";
                        }
                        if(climate%5 == 4){
                            value = "多云";
                        }
                    }

                    // 时间处理
                    if(fieldName.equals("time")){
                        int climate = Integer.parseInt(listMap.get("time").get(i));
                        Date date = DateUtils.addDays(new Date(),climate);
                        value = DateUtils.parseDateToStr(YYYY_MM_DD,date);
                    }

                    // 风向处理
                    if(fieldName.equals("wind")){
                        int climate = Math.abs(Integer.parseInt(listMap.get("wind").get(i)));
                        if(climate%4 == 0){
                            value = "东风 "+climate%9+"级";
                        }
                        if(climate%4 == 1){
                            value = "南风 "+climate%9+"级";
                        }
                        if(climate%4 == 2){
                            value = "西风 "+climate%9+"级";
                        }
                        if(climate%4 == 3){
                            value = "北风 "+climate%9+"级";
                        }
                    }
                    list.add(value);
                }
                rowList.add(list);
            }
        }
        params.put("data", rowList);

        // 开始入库
        updateMsgByprocess(processList, "数据库开始准备入库", redisId, Constants.FLAG_5);
        dynamicMapper.insertData(params); // 插入数据
        Thread.sleep(random.nextInt(1001) + 1000);


        // 开始生成数据
        updateMsgByprocess(processList, "模拟数据入库完成", redisId, Constants.FLAG_6);
        Thread.sleep(random.nextInt(1001) + 1500);
        updateMsgByprocess(processList, "模拟生成数据结束", redisId, Constants.FLAG_0);
        dataTableVo.setStatus(Constants.FLAG_0);
        return dataTableVo;
    }

    private List<ProcessData> updateMsgByprocess(List<ProcessData> processList, String msg, String redisId, Integer status) {
        String time = DateUtils.dateTimeNow(YYYY_MM_DD_HH_MM_SS) + ":";
        List<ProcessData> updateList = new ArrayList<>();
        ProcessData processData = new ProcessData();
        processData.setStatus(status);
        processData.setMsg(time + msg);
        processList.add(processData);
        updateList.add(processData);
        // 更新redis
        redisService.setCacheList(redisId, updateList, 5);
        return processList;
    }

    @Override
    public Map<String, Object> getProgress(DataTableReq dataTableReq) {
        Map<String, Object> processMap = new HashMap<>();
        String redisId = RedisConstants.PROGRESS_ + dataTableReq.getTemplateId() + "_" + dataTableReq.getUuid();
        List<ProcessData> progressList = redisService.getCacheList(redisId);
        Integer status = progressList.get(progressList.size() - 1).getStatus();
        processMap.put("processList", progressList);
        processMap.put("msg", getMsgByStatus(status));
        processMap.put("status", status);
        return processMap;
    }

    /**
     * 发送数据
     * @param dataTableReq
     * @return
     * @throws InterruptedException
     */
    @Override
    public DataTableVo sendData(DataTableReq dataTableReq) throws InterruptedException {
        DataTableVo dataTableVo = new DataTableVo();
        List<ProcessData> processList = new ArrayList<>();
        String redisId = RedisConstants.SEND_ + dataTableReq.getTemplateId() + "_" + dataTableReq.getUuid();
//        redisService.setCacheList(RedisConstants.PROGRESS_ + dataTableReq.getUuid(), processList, 5);

        // 数据生成进度
        updateMsgByprocess(processList, "开始发送数据", redisId, Constants.FLAG_1);

        // 建立连接
        Random random = new Random();
        updateMsgByprocess(processList, "正在建立连接", redisId, Constants.FLAG_2);
        Thread.sleep(random.nextInt(1001) + 1500);
        updateMsgByprocess(processList, "建立连接成功", redisId, Constants.FLAG_2);

        // 开始生成数据
        Map<String, Object> params = new HashMap<>();
        updateMsgByprocess(processList, "开始发送数据", redisId, Constants.FLAG_3);
        // 模拟数据
        Thread.sleep(random.nextInt(1001) + 1500);
        updateMsgByprocess(processList, "收到对方反馈", redisId, Constants.FLAG_4);
        Thread.sleep(random.nextInt(1001));
        updateMsgByprocess(processList, "数据发送结束", redisId, Constants.FLAG_0);
        dataTableVo.setStatus(Constants.FLAG_0);
        return dataTableVo;
    }

    @Override
    public Map<String, Object> sendProgress(DataTableReq dataTableReq) {
        Map<String, Object> processMap = new HashMap<>();
        String redisId = RedisConstants.SEND_ + dataTableReq.getTemplateId() + "_" + dataTableReq.getUuid();
        List<ProcessData> progressList = redisService.getCacheList(redisId);
        if(CollectionUtils.isNotEmpty(progressList)){
            Integer status = progressList.get(progressList.size() - 1).getStatus();
            processMap.put("processList", progressList);
            processMap.put("msg", getMsgBySendStatus(status));
            processMap.put("status", status);
        }else{
            processMap.put("processList", progressList);
            processMap.put("msg", getMsgBySendStatus(3));
            processMap.put("status", 0);
        }
        return processMap;
    }

    public String getMsgByStatus(Integer status) {
        switch (status) {
            case 0:
                return "模拟生成数据结束";
            case 1:
                return "开始模拟生成数据";
            case 2:
                return "开始读取数据初始化配置";
            case 3:
                return "读取python脚本完成";
            case 4:
                return "脚本生成模拟数据";
            case 5:
                return "模拟数据准备入库";
            case 6:
                return "模拟数据入库完成";
            default:
                return "";
        }
    }

    public String getMsgBySendStatus(Integer status) {
        switch (status) {
            case 0:
                return "";
            case 1:
                return "开始发送数据";
            case 2:
                return "正在建立连接";
            case 3:
                return "数据传输完成";
            case 4:
                return "收到对方反馈";
            default:
                return "";
        }
    }
}
